# sums
1+12
This second document follows on from Tutorial 1: “Getting started” and assumes that you’re still working in your active project.
This document covers the following:
There is also a section at the end with some “Quick tips”.
As you probably can guess, the REPL is an interface onto a large calculator. Julia does all the things R does… and you can find the basic maths operations defined The Julia Manual
# sums
1+12
# power
10^31000
# sequences in a vector
# From 0, by 1, to 10...
x = collect(0:1:10)
# see it
x11-element Vector{Int64}:
0
1
2
3
4
5
6
7
8
9
10
# multply scaler x vector.
x*1011-element Vector{Int64}:
0
10
20
30
40
50
60
70
80
90
100
Before we move on, lets talk about the help files and how to access them. As in R, the help files assiocated with a given package, function or command can be accessed using ? followed by the function name (e.g. type ? pi in the REPL).
Similar to when you entered Julia’s package manager (using ]) you’ll notice that the ? command causes a change in the REPL with help?>replacing julia> as the prompt. This informs you that you’ve entered the help mode. As an exercise, use the help mode to find the difference between print and println.
Before we start creating arrays and matrices, we’d like to demonstrate how you allocate numbers and strings to objects in Julia and check an object’s type. We’d also like to highlight some simple mathematical operations.
Allocating in Julia is useful as it means that variables can be stored and used elsewhere. You allocate numbers to objects using the following:
First note that we use the = in Julia, not the <- as in R.
# allocate an Integer number to a variable
n = 55
Julia, like other languages, has some built in values, like pi. We can allocate these to variable names we will use. Notice that Julia converts pi into the unicode symbol!
# allocate a pre-defined number of importance to a variable
# note that pi is converted to π
# note2 - you can use \pi in a julia script to get the unicode π ...
# this works for numerous greek letters etc. Like \lambda for λ
pi_sum = pi
pi_sumπ = 3.1415926535897...
We can use these unicode symbols, like λ, as objects
λ = 4
λ4
You can also assign multiple values to separate variables in a concise manner. Julia can manage something like this:
αi, βi, γi = 1.3, 2.1, exp(39)
# confirm...
αi, βi, γi(1.3, 2.1, 8.659340042399374e16)
Of course you can also allocate strings of text to objects. You must use the "" and not '' to define strings.
sob = "School of Biosciences""School of Biosciences"
You can combine strings and numbers to print like this. Note how you use $object.name within the text string you are writing… and this works for objects that are text or numeric.
println("The favourite number in $sob is $n")The favourite number in School of Biosciences is 5
Julia is very specific about types of objects. Most programming languages are. One way to learn about them is to look at what is made when you make things in different ways.
typeof(n), typeof(sob), typeof(pi)(Int64, String, Irrational{:π})
Julia is like R and Python in that it can infer the type of object (Integer, Float, etc) on the left hand side of the equals sign - you don’t have to justify it like you do in C. However, you can declare the type if needed e.g.
pi_custom = Float64(3.141592)3.141592
For those of you that are interested, a floating-point object (a Float) is a number that has a decimal place. An Int object is an integer, a number without a decimal place, whereas an Irrational object is a specific type of Float used only for representing some irrational numbers of special significance (e.g. π and γ). The 64 purely refers to 64-bit which is the type of processor your computer uses, most modern computers are 64-bit.
Occasionally it will be valuable to convert an object from one type to another. For example, n is currently an Integer (Int64), and we might want it to be Float (Float64). To be clear, this is a distinction between 5 and 5.0!
typeof(n)Int64
n2 = convert(Float64, n)
typeof(n2)Float64
As you saw above, we created a sequence of numbers using collect(0:1:10). Let’s look at what type of object this is:
typeof(x)Vector{Int64} (alias for Array{Int64, 1})
This is a vector. Let’s step back to see the difference between arrays and vectors. Arrays, for the R users, are best thought of as lists - they are storage boxes for any type of variables and can contain collections of various types. The general way to create an array, in this case and empty one, is the [ ].
empty_array = []Any[]
We will first create an array with the same values as x and then see how collect() is the function that converts this to a vector, and actually lets us see the numbers too!
First, range can be used to make an array. This is very similar to seq() in R and has the two variations - by and length that the R function has. The idfference is that by is replaced by the argument step. Note how a very concise summary of this array is presented using information in square brackets [ ]:
x_array1 = range(start = 1, step = 1, stop = 10)
x_array2 = range(start = 1, stop = 10, length = 5)
x_array1, x_array2(1:1:10, 1.0:2.25:10.0)
You can also now see that creating arrays is possible with [ ] and the use of the : :
x_array3 = [1:1:10]1-element Vector{StepRange{Int64, Int64}}:
1:1:10
Quite often, you want to either see the values, or specifically be using a vector. To do this, you can use the function collect():
collect(x_array1)10-element Vector{Int64}:
1
2
3
4
5
6
7
8
9
10
You should recall from R that values in arrays and vectors and dataframes have addresses that we call indices. Julia works with indexing very similarly.
Let’s make a simple array of 5 numbers and another simple array of five words. Note that the [] array function is a but like the c() function in R.
ar = [6,7,8,9,10]
br = ["Pint", "of", "Moonshine", "please"]4-element Vector{String}:
"Pint"
"of"
"Moonshine"
"please"
You can get any address in these using… square brackets!
ar[2] # gets the number 7!7
br[3] # gets the word Moonshine"Moonshine"
If you want two addresses in a sequence, you can just provide the sequence:
ar[2:3]2-element Vector{Int64}:
7
8
But if you want non-adjacent values, you need to provide the ‘list of indices’ as an array, which results in the use of [[ ]].
ar[[2,4]]2-element Vector{Int64}:
7
9
Note this would be like using in R ar[c(2,4)].
Broadcasting allows you to apply a function, like a log() or exp(), in an element-wise manner to an array (in other words apply the function to every element of an array).
We saw above that we can create a vector using collect() and multiply this by a scalar
# sequences in a vector
# From 0, by 1, to 10...
x = collect(0:1:10)
# see it
x11-element Vector{Int64}:
0
1
2
3
4
5
6
7
8
9
10
# multply scaler x vector.
x*1011-element Vector{Int64}:
0
10
20
30
40
50
60
70
80
90
100
You can work directly with arrays and pre-built functions to do things like this. To do-so, we combine the function with the (dot) . operator. Let’s work with x_array1 from above. Note how broadcasting the function across the array returns a vector.
# Look at the help file for exp10
exp_array1 = exp10.(x_array1)10-element Vector{Float64}:
10.0
100.0
1000.0
10000.0
100000.0
1.0e6
1.0e7
1.0e8
1.0e9
1.0e10
# look at the help file for log - what is the default!?
log_array1 = log.(x_array1)10-element Vector{Float64}:
0.0
0.6931471805599453
1.0986122886681098
1.3862943611198906
1.6094379124341003
1.791759469228055
1.9459101490553132
2.0794415416798357
2.1972245773362196
2.302585092994046
Did you check the help file for log? Is it the same default as we find in R?
Sometimes we’ll be interested in a 2-dimensional or higher version of the array/vector, and this is a matrix. Making a matrix in Julia uses the [ ] again, an separates rows of numbers with the ;
mat = [1 2 3; 4 5 6]2×3 Matrix{Int64}:
1 2 3
4 5 6
Note how there are NO commas between the numbers in each row! This is read as ‘rows are separated by ; and columns by spaces’!
You can also ‘pre-fill’ a matrix with zeros. This is good practice in loops and programming as pre-filling and replacing variables in a matrix is more efficient than creating the matrix on the fly. Here we demonstrate how to pre-fil a vector, matrix and high dimension array! Matrices can have more than two dimensions!
vec0 = zeros(2) # 2 zeros allocated in a vector2-element Vector{Float64}:
0.0
0.0
mat0 = zeros(2,3) # zeros allocated to 2 rows and 3 columns!2×3 Matrix{Float64}:
0.0 0.0 0.0
0.0 0.0 0.0
arr0 = zeros(2,3,4) # 2 rows, 3 columns and 4 dimensions!2×3×4 Array{Float64, 3}:
[:, :, 1] =
0.0 0.0 0.0
0.0 0.0 0.0
[:, :, 2] =
0.0 0.0 0.0
0.0 0.0 0.0
[:, :, 3] =
0.0 0.0 0.0
0.0 0.0 0.0
[:, :, 4] =
0.0 0.0 0.0
0.0 0.0 0.0
Accessing values in a matrix follows the same convention as with the vector. The convention is [row, column]
mat[1,2] # value in the first row and second column2
mat[1:2, 3] # rows 1 AND 2 in the 3rd column2-element Vector{Int64}:
3
6
Finally, to get a row or column, you need to know that we need a placeholder for the missing bit of what you are asking for. If we want the second row, we ask for row 2, and stick the : placeholder in the column spot:
mat[2,:]3-element Vector{Int64}:
4
5
6
For a column, we reverse this.
mat[:,2]2-element Vector{Int64}:
2
5